package com.example.springboot3demo.util;

import java.util.ArrayList;
import java.util.List;

public class SecurityDecoder {

    private static final String FIXED_A = "RDpbLfCPsJZ7fiv";
    private static final String FIXED_C = "yLwVl0zKqws7LgKPRQ84Mdt708T1qQ3Ha7xv3H7NyU84p21BriUWBU43odz3iP4rBL3cD02KZciXTysVXiV8ngg6vL48rPJyAUw0HurW20xqxv9aYb4M9wK1Ae0wlro510qXeU07kV57fQMc8L6aLgMLwygtc0F10a0Dg70TOoouyFhdysuRMO51yY5ZlOZZLEal1h0t9YQW0Ko7oBwmCAHoic4HYbUyVeU3sfQ1xtXcPcf1aT303wAQhv66qzW";

    /**
     * 解密主方法
     * @param ciphertext 密文
     * @return 可能的原文列表(可能有多个解)
     */
    public static List<String> decode(String ciphertext) {
        List<String> possibleInputs = new ArrayList<>();
        int maxLength = Math.max(FIXED_A.length(), ciphertext.length());

        // 先确定输入长度
        int inputLength = determineInputLength(ciphertext);
        if (inputLength == -1) {
            System.out.println("无法确定输入长度，密文可能无效");
            return possibleInputs;
        }

        // 逐个字符解密
        char[] inputChars = new char[inputLength];
        backtrack(0, inputChars, ciphertext, possibleInputs);

        return possibleInputs;
    }

    // 确定输入原文的可能长度
    private static int determineInputLength(String ciphertext) {
        // 检查密文尾部是否由固定部分生成
        for (int len = 0; len <= FIXED_A.length(); len++) {
            boolean match = true;
            for (int p = len; p < ciphertext.length() && p < FIXED_A.length(); p++) {
                char expected = FIXED_C.charAt((FIXED_A.charAt(p) ^ 187) % FIXED_C.length());
                if (ciphertext.charAt(p) != expected) {
                    match = false;
                    break;
                }
            }
            if (match) {
                return len;
            }
        }
        return -1;
    }

    // 递归回溯尝试所有可能的字符组合
    private static void backtrack(int pos, char[] current, String ciphertext, List<String> results) {
        if (pos >= current.length) {
            results.add(new String(current));
            return;
        }

        char targetChar = ciphertext.charAt(pos);
        char aChar = pos < FIXED_A.length() ? FIXED_A.charAt(pos) : (char)187;

        // 找出所有可能的bChar使得 (aChar ^ bChar) % k = indexOf(targetChar)
        int targetIndex = FIXED_C.indexOf(targetChar);
        if (targetIndex == -1) {
            return;  // 无效字符
        }

        // 由于取模运算，可能有多个解
        for (int bChar = 0; bChar < 65536; bChar++) {  // 遍历所有可能的char值
            if ((aChar ^ bChar) % FIXED_C.length() == targetIndex) {
                current[pos] = (char)bChar;
                backtrack(pos + 1, current, ciphertext, results);
            }
        }
    }

    // 优化版的解密方法(针对可打印ASCII字符)
    public static List<String> decodeOptimized(String ciphertext) {
        List<String> possibleInputs = new ArrayList<>();
        int inputLength = determineInputLength(ciphertext);
        if (inputLength == -1) return possibleInputs;

        char[] input = new char[inputLength];
        decodeChar(0, input, ciphertext, possibleInputs);
        return possibleInputs;
    }

    private static void decodeChar(int pos, char[] current, String ciphertext, List<String> results) {
        if (pos >= current.length) {
            results.add(new String(current));
            return;
        }

        char targetChar = ciphertext.charAt(pos);
        char aChar = pos < FIXED_A.length() ? FIXED_A.charAt(pos) : (char)187;
        int targetIndex = FIXED_C.indexOf(targetChar);
        if (targetIndex == -1) return;

        // 只尝试可打印ASCII字符(32-126)
        for (int bChar = 32; bChar <= 126; bChar++) {
            if ((aChar ^ bChar) % FIXED_C.length() == targetIndex) {
                current[pos] = (char)bChar;
                decodeChar(pos + 1, current, ciphertext, results);
            }
        }
    }

    public static void main(String[] args) {
        String targetCipher = "0lB408bWi5qfbwK";

        System.out.println("尝试解密: " + targetCipher);
        System.out.println("可能的结果:");

        List<String> possibleInputs = decodeOptimized(targetCipher);
        for (String input : possibleInputs) {
            System.out.println(input + " -> " + SecurityEncoder.orgAuthPwd(input));
        }
    }
}
